/*
	BlockShaper class
	Written by
	Version 1.0

	input data chunk with any size
	output block data with fixed size

Example:

BlockShaper	bs;

...

if (!bs.Init(BLOCK_SIZE, BLOCK_SIZE/2))	// such as: BLOCK_SIZE = 192
	return false;

...

char	*pData=pInputData;
int		nLen=nInputLen;
while (nLen) {
	bs.Feed(pData, nLen);
	char	*pBlock = bs.GetBlock();
	if (pBlock) {
		...	// do what you want to do with this block data
	}
}

...

*/


#if !defined(_BLOCK_SHAPER_H_)
#define _BLOCK_SHAPER_H_

#include <cstring>


class BlockShaper
{
public:
	BlockShaper(){
		m_pBlock = NULL;
	};

	~BlockShaper(){
		Reset();
	};

	bool Init(int nBlockSize, int nShiftSize){
		if (nBlockSize <= 0 || nShiftSize <=0)
			return false;
		Reset();
		m_pBlock = new char[nBlockSize];
		if (!m_pBlock)
			return false;
		m_nBlockSize = nBlockSize;
		m_nShiftSize = nShiftSize;
		m_nBlockPos = 0;
		return true;
	};

	void Reset(){
		Clear();
		if (m_pBlock) {
			delete[] m_pBlock;
			m_pBlock = NULL;
		}
	};

	void Clear(){
		m_nBlockPos = 0;
	};


	bool Feed(char *&pData, int &nLen){
		if (!pData || nLen < 0)
			return false;
		if (!m_pBlock)
			return false;
		if (m_nBlockPos < 0) {
			int	nFill = -m_nBlockPos;
			if (nFill > nLen)
				nFill = nLen;
			m_nBlockPos += nFill;
			pData += nFill;
			nLen -= nFill;
			if (m_nBlockPos < 0)
				return true;
		}
		else if (m_nBlockPos == m_nBlockSize+1) {
			m_nBlockPos = m_nBlockSize - m_nShiftSize;
			memmove(m_pBlock, m_pBlock+m_nShiftSize, m_nBlockPos);
		}
		int	nUsable = m_nBlockSize - m_nBlockPos;
		if (nUsable > nLen)
			nUsable = nLen;
		memcpy(m_pBlock+m_nBlockPos, pData, nUsable);
		m_nBlockPos += nUsable;
		pData += nUsable;
		nLen -= nUsable;
		return true;
	};

	char *GetBlock(){
		if (!m_pBlock || m_nBlockPos != m_nBlockSize)//	block
			return NULL;
		m_nBlockPos -= m_nShiftSize;
		if (m_nBlockPos > 0)
			m_nBlockPos = m_nBlockSize + 1;	// a flag value to indicate overlap
		return m_pBlock;
	};

	char *GetRemain(int &nLen){
		if (!m_pBlock)
			return NULL;
		nLen = m_nBlockPos;
		return m_pBlock;
	};

	int  BlockSize() { return m_nBlockSize; }
	int GetShiftSize() { return m_nShiftSize; }
	int GetBlockPos(){return m_nBlockPos;}

private:
	char	*m_pBlock;
	int		m_nBlockSize;
	int		m_nShiftSize;
	int		m_nBlockPos;
};


#endif
